/**
 * Library: ER Model
 * 
 * Class: Table
 * 	This class represents a table of a relational database
 * 
 * $$Id:$$
 * 
 */
package com.googlecode.cardamomo.ermodel;

import java.util.Iterator;
import java.util.Vector;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;

/**
 * Table is the main element in the model
 * @author jtorne
 *
 */
@XmlType(namespace = DataType.CARDAMOMO_NAMESPACE,
		propOrder = { "name", "type", "label", "comment", "imports", "columns",
		"primaryKeyIndex", "indexes", "foreignKeys", "lookups" })
@XmlRootElement
public class Table {

	// currentTable is the latest created Table object
	private static Table currentTable = null;
	
	// Attributes
	protected String name;
	protected String type;
	protected String label;
	protected String comment;
	protected Vector<Column> columns = new Vector<Column>();
	protected Vector<Index> indexes = new Vector<Index>();
	protected Index primaryKeyIndex = null;
	protected Vector<Import> imports = null;
	protected Vector<ForeignKey> fkeys = new Vector<ForeignKey>();
	protected Vector<Lookup> lookups = new Vector<Lookup>();

	@XmlTransient
	private DataDictionary dict = null;

	/*=== Constructors ===*/
	
	public Table() {
		currentTable = this;
	}

	public Table(String name) {
		currentTable = this;
		setName(name);
	}

	/*=== static methods ===*/
	
	public static Table getCurrentTable() {
		return currentTable;
	}

	/*=== getters & setters ===*/
	
	@XmlAttribute(required = true)
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@XmlAttribute
	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	@XmlAttribute(name="label")
	public String getLabel() {
		if (label == null)
			return getName();
		return label;
	}

	public void setLabel(String label) {
		this.label = label;
	}

	@XmlElementWrapper(name = "indexes")
	@XmlElement(name = "index")
	public Vector<Index> getIndexes() {
		return indexes;
	}

	public void setIndexes(Vector<Index> indexes) {
		this.indexes = indexes;
	}

	@XmlTransient
	public int getIndexCount() {
		int i = 0;
		if (hasPrimaryKey()) i++;
		return i + getIndexes().size();
	}

	@XmlElementWrapper(name = "foreignKeys")
	@XmlElement(name = "foreignKey")
	public Vector<ForeignKey> getForeignKeys() {
		return fkeys;
	}
	
	public void setForeignKeys(Vector<ForeignKey> foreignKeys) {
		this.fkeys = foreignKeys;
	}

	/**
	 * Primary key constraint is similar to an index, so we'll
	 * represented with an Index object.
	 * 
	 * @return
	 */
	@XmlElement(name="primaryKey")
	public Index getPrimaryKeyIndex() {
		return primaryKeyIndex;
	}

	public void setPrimaryKeyIndex(Index primaryKey) {
		this.primaryKeyIndex = primaryKey;
		for (Column col : getColumns()) {
			col.setPrimaryKey(primaryKey.contains(col.getName()));
		}
	}

	public boolean hasPrimaryKey() {
		return primaryKeyIndex != null && primaryKeyIndex.getKeyCount() > 0;
	}

	@XmlElementWrapper(name = "columns")
	@XmlElement(name = "column")
	public Vector<Column> getColumns() {
		return columns;
	}

	public void setColumns(Vector<Column> columns) {
		this.columns = columns;
	}

	@XmlTransient
	public int getColumnCount() {
		if (columns != null)
			return columns.size();
		return 0;
	}

	public Column getColumnAt(int i) {
		return columns.get(i - 1);
	}

	public Column getColumn(String name) {
		for (Iterator<Column> ci = columns.iterator(); ci.hasNext();) {
			Column cm = ci.next();
			if (cm.getName().equalsIgnoreCase(name))
				return cm;
		}
		return null;
	}

	@XmlElementWrapper(name = "imports")
	@XmlElement(name = "import")
	public Vector<Import> getImports() {
		return imports;
	}

	public void setImports(Vector<Import> imports) {
		this.imports = imports;
	}

	@XmlElement
	public String getComment() {
		return comment;
	}

	public void setComment(String comment) {
		if (comment == null)
			return;
		this.comment = comment;
	}

	@XmlElementWrapper(name = "lookups")
	@XmlElement(name = "lookup")
	public Vector<Lookup> getLookups() {
		return lookups;
	}
	
	public void setLookups(Vector<Lookup> lookups) {
		this.lookups = lookups;
	}
	public ForeignKey getForeignKey(String name) {
		if (getForeignKeys() == null)
			setForeignKeys(new Vector<ForeignKey>());
		for (int i = 0; i < fkeys.size(); i++)
			if (fkeys.get(i).getName().equals(name))
				return fkeys.get(i);
		ForeignKey fk = new ForeignKey();
		fk.setName(name);
		fkeys.add(fk);
		return fk;
	}
	
	public Index getIndex(String iname) {
		// System.err.println("Table.getIndex "+iname);
		if (getIndexes() == null)
			setIndexes(new Vector<Index>());
		for (int i = 0; i < indexes.size(); i++)
			if (indexes.get(i).getName().equals(iname))
				return indexes.get(i);
		Index im = new Index();
		im.setName(iname);
		indexes.add(im);
		return im;
	}

	@XmlTransient
	public DataDictionary getDictionary() {
		if (dict == null) {
			dict = new DataDictionary();
			dict.setParentDict(DataDictionary.defaultInstance());
		}
		return dict;
	}

	public void addPrimaryKey(String iname, short ordinal, boolean asc) {
		if (primaryKeyIndex == null)
			primaryKeyIndex = new Index();
		primaryKeyIndex.setName("PK_" + name);
		primaryKeyIndex.addKey(ordinal, iname, asc);
		primaryKeyIndex.setUnique(true);
	}

	public void addIndex(Index index) {
		// System.err.println("Table.addIndex "+index);
		if (indexes == null)
			indexes = new Vector<Index>();
		for (int i = 0; i < indexes.size(); i++)
			if (indexes.get(i).getName().equals(index.getName()))
				return;
		indexes.add(index);
	}

	@Override
	public String toString() {
		return "Table " + getName() + " is " + getType() + ": " + getComment()
				+ " / " + getColumns() + " / " + getIndexes();
	}


}
